# -*- coding: utf-8 -*-
# @Time    : 2024/7/25 08:50
# @Author  : Jonny
# @File    : LuckGitlabLogService.py

from luck.gitlab.LuckGitlabApi import LuckGitlabApi
from luck.util.LuckDbMysqlHelperUtils import LuckDbMysqlHelperUtils
from luck.core.LuckConstant import LuckConstant
from luck.gitlab.LuckGitlabUserService import LuckGitlabUserService
import uuid
from datetime import datetime
import json
from luck.gitlab.LuckGitlabFileService import LuckGitlabFileService


class LuckGitlabLogService(object):

    def __init__(self, config):
        self.config = config
        self.gitlab_api = LuckGitlabApi(self.config["gitlab_private_token"], self.config["gitlab_server_url"])

    TABLE_NAME = "luck_gitlab_log"

    def get_gitlab_data(self, start_time, end_time, project_code1):
        """
        Get data from GitLab API
        """
        data_list = []

        try:
            gitllab_user_service = LuckGitlabUserService(self.config)
            projects = self.gitlab_api.read_all_projects()
            print(f"共 {len(projects)} 个项目")
            num = 0
            for project in projects:
                project_web_url = project.web_url
                project_visibility = project.visibility
                project_path = project.path
                project_name_with_namespace = project.name_with_namespace
                project_path_with_namespace = project.path_with_namespace
                project_name = project.name
                project_id = project.id
                project_description = project.description
                description_list = project_description.split("/")
                project_code = ""
                if len(description_list) > 1:
                    project_code = description_list[len(description_list) - 1]  # 读取最后一个/杠后面的项目编号
                # 如果project_code不为空，则说明要读取指定项目的用户贡献信息
                if project_code1 is not None and len(project_code1) > 0 and project_code1 != project_code:
                    continue

                num += 1
                branches = project.branches.list()
                print(f"第 {num} 个项目，有 {len(branches)} 个分支")
                brach_num = 0
                for branch in branches:
                    commits = project.commits.list(all=True, query_parameters={'since': start_time, 'until': end_time,
                                                                               'ref_name': branch.name})
                    brach_num += 1
                    print(f"第 {brach_num} 个 {branch.name} 分支提交了{len(commits)}次")
                    for commit in commits:
                        # 获取提交详情
                        commit_info = project.commits.get(commit.id)
                        # 获取修改的文件
                        diff = commit_info.diff(get_all=True)
                        # 输出文件数量和文件列表
                        commit_file_list = []
                        commit_new_file_list = []
                        commit_renamed_file_list = []
                        commit_deleted_file_list = []
                        commit_updated_file_list = []
                        for change in diff:
                            change["diff"] = ""
                            commit_file_list.append(change)
                            if change["new_file"] == True:
                                commit_new_file_list.append(change)
                            elif change["renamed_file"] == True:
                                commit_renamed_file_list.append(change)
                            elif change["deleted_file"] == True:
                                commit_deleted_file_list.append(change)
                            else:
                                commit_updated_file_list.append(change)

                        data = {}

                        data["project_name_with_namespace"] = project_name_with_namespace
                        data["project_name"] = project_name
                        data["project_id"] = project_id
                        data["project_code"] = project_code
                        data["project_description"] = project_description
                        data["project_path"] = project_path
                        data["project_path_with_namespace"] = project_path_with_namespace
                        data["project_web_url"] = project_web_url
                        data["project_visibility"] = project_visibility

                        data["branch_name"] = branch.name

                        data["commit_file_count"] = len(commit_file_list)
                        data["commit_new_file_count"] = len(commit_new_file_list)
                        data["commit_renamed_file_count"] = len(commit_renamed_file_list)
                        data["commit_deleted_file_count"] = len(commit_deleted_file_list)
                        data["commit_updated_file_count"] = len(commit_updated_file_list)

                        data["commit_file_list"] = commit_file_list
                        data["commit_new_file_list"] = commit_new_file_list
                        data["commit_renamed_file_list"] = commit_renamed_file_list
                        data["commit_deleted_file_list"] = commit_deleted_file_list
                        data["commit_updated_file_list"] = commit_updated_file_list

                        data["commit_id"] = commit_info.id
                        data["commit_short_id"] = commit_info.short_id

                        commit_title = commit_info.title.replace("'", " ")
                        data["commit_title"] = commit_title

                        commit_message = commit_info.message.replace("'", " ")
                        data["commit_message"] = commit_message
                        data["commit_author_account"] = commit_info.committer_name
                        data["commit_author_email"] = commit_info.committer_email
                        # 获取指定用户账号的用户信息
                        user_list = self.gitlab_api.read_user_by_username(data["commit_author_account"])
                        if len(user_list) > 0:
                            for u in user_list:
                                data["commit_author_name"] = u["name"]
                                data["commit_author_avatar_url"] = u["avatar_url"]
                                data["commit_author_web_url"] = u["web_url"]
                        else:
                            user_list = gitllab_user_service.read_by_commit_author_account(data["commit_author_account"])["data"]
                            if len(user_list) > 0:
                                for u in user_list:
                                    data["commit_author_name"] = u["user_name"]
                                    data["commit_author_avatar_url"] = u["user_avatar_url"]
                                    data["commit_author_web_url"] = u["user_web_url"]

                        # 原始时间戳，包含时区信息
                        timestamp_with_tz = commit_info.committed_date
                        # 移除时区信息
                        timestamp_without_tz = timestamp_with_tz.split('+')[0]
                        # 使用strptime将时间戳转换为datetime对象
                        dt_obj = datetime.strptime(timestamp_without_tz, '%Y-%m-%dT%H:%M:%S.%f')
                        # 如果你确定不需要毫秒，可以直接这样做：
                        formatted_dt_no_ms = dt_obj.strftime('%Y-%m-%d %H:%M:%S')
                        data["commit_date"] = formatted_dt_no_ms

                        data["commit_additions"] = commit_info.stats["additions"]
                        data["commit_deletions"] = commit_info.stats["deletions"]
                        data["commit_total"] = commit_info.stats["total"]

                        data_list.append(data)
                        print(f"提交信息为：{data}")
        except Exception as e:
            print(f"有错误, 请检查: {e}")
        finally:
            return data_list

    # 处理数据
    def process_data(self, start_time, end_time, project_code):
        for row in self.get_gitlab_data(start_time, end_time, project_code):
            # 过滤掉管理员和提交总数为0的提交信息
            if (row["commit_author_account"] == "Administrator" or row["commit_author_account"] == "root" or row["commit_author_account"] == "lucksoft"):
                continue
            parameters = row

            read_logs = self.read({
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"]
            })["data"]
            # 存在就更新，不存在就添加
            if len(read_logs) > 0:
                for log in read_logs:
                    parameters["id"] = log["id"]
                    self.update(parameters)
            else:
                self.add(parameters)

    # 添加日志
    def add(self, parameters):
        parameters["id"] = str(uuid.uuid4())  # 生成UUID作为主键
        parameters["version"] = 1
        parameters["regt"] = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")

        if "commit_file_list" in parameters:
            del parameters["commit_file_list"]

        commit_new_file_list = []
        if "commit_new_file_list" in parameters:
            commit_new_file_list = parameters["commit_new_file_list"]
            del parameters["commit_new_file_list"]

        commit_renamed_file_list = []
        if "commit_renamed_file_list" in parameters:
            commit_renamed_file_list = parameters["commit_renamed_file_list"]
            del parameters["commit_renamed_file_list"]

        commit_deleted_file_list = []
        if "commit_deleted_file_list" in parameters:
            commit_deleted_file_list = parameters["commit_deleted_file_list"]
            del parameters["commit_deleted_file_list"]

        commit_updated_file_list = []
        if "commit_updated_file_list" in parameters:
            commit_updated_file_list = parameters["commit_updated_file_list"]
            del parameters["commit_updated_file_list"]

        # 构建字段名和参数列表
        fields = []
        values = []
        for key, value in parameters.items():
            if value is not None:
                fields.append(key)
                if isinstance(value, dict):
                    # 如果value是dict类型，先将其转换为json字符串
                    values.append(json.dumps(value))
                else:
                    # 对于非dict类型，直接添加value
                    values.append(value)

        # 构建SQL日志
        placeholders = ', '.join(['?'] * len(fields))
        sql_template = f"INSERT INTO {self.TABLE_NAME} ({', '.join(fields)}) VALUES ({placeholders})"
        # 输出日志（使用占位符以避免日志中的SQL注入风险）
        logging_placeholders = ', '.join(['%s'] * len(fields))
        logging_sql = f"添加日志语句：INSERT INTO {self.TABLE_NAME} ({', '.join(fields)}) VALUES ({logging_placeholders})"
        print(logging_sql % tuple(values))

        db_host = self.config["db_host"]
        db_port = self.config["db_port"]
        db_name = self.config["db_name"]
        db_user = self.config["db_user"]
        db_password = self.config["db_password"]
        db_helper = LuckDbMysqlHelperUtils(db_host, db_port, db_name, db_user, db_password)
        with db_helper as um:
            sql_template = sql_template.replace("?", "%s")
            um.cursor.execute(sql_template, values)

        obj = self.read({
            "id": parameters["id"]
        })["data"][0]

        gitlab_file_service = LuckGitlabFileService(self.config)
        # 先删除，在添加
        read_files = gitlab_file_service.read({
            "project_id": parameters["project_id"],
            "branch_name": parameters["branch_name"],
            "commit_id": parameters["commit_id"]
        })["data"]
        for file in read_files:
            gitlab_file_service.delete({
                "id": file["id"]
            })
        for file in commit_new_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "new_file",
                "commit_file_diff": file["diff"]
            })
        for file in commit_renamed_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "renamed_file",
                "commit_file_diff": file["diff"]
            })
        for file in commit_deleted_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "deleted_file",
                "commit_file_diff": file["diff"]
            })
        for file in commit_updated_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "updated_file",
                "commit_file_diff": file["diff"]
            })

        return {
            "code": LuckConstant.CODE_SUCCESS,
            "msg": "操作成功",
            "data": obj
        }

    # 修改日志
    def update(self, parameters):
        parameters["modt"] = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")

        if "commit_file_list" in parameters:
            del parameters["commit_file_list"]

        commit_new_file_list = []
        if "commit_new_file_list" in parameters:
            commit_new_file_list = parameters["commit_new_file_list"]
            del parameters["commit_new_file_list"]

        commit_renamed_file_list = []
        if "commit_renamed_file_list" in parameters:
            commit_renamed_file_list = parameters["commit_renamed_file_list"]
            del parameters["commit_renamed_file_list"]

        commit_deleted_file_list = []
        if "commit_deleted_file_list" in parameters:
            commit_deleted_file_list = parameters["commit_deleted_file_list"]
            del parameters["commit_deleted_file_list"]

        commit_updated_file_list = []
        if "commit_updated_file_list" in parameters:
            commit_updated_file_list = parameters["commit_updated_file_list"]
            del parameters["commit_updated_file_list"]

        if "id" not in parameters or ("id" in parameters and len(parameters["id"]) <= 0):
            return {
                "code": LuckConstant.CODE_FAIL,
                "msg": "id不能为空"
            }
        id_value = parameters["id"]
        old_obj = self.read({
            "id": id_value
        })["data"][0]
        parameters["version"] = float(old_obj["version"])+1

        # 遍历parameters字典，并构建SET子句的条件
        conditions = []
        for key, value in parameters.items():
            if value is not None:
                if isinstance(value, dict):
                    value = json.dumps(value)
                conditions.append(f"{key} = '{value}'")
        # 如果存在条件，将它们用英文逗号连接起来，并添加到SQL查询中
        sql_update = ""
        if conditions:
            sql_update = ", ".join(conditions)
        sql = f"update {self.TABLE_NAME} set {sql_update} where id='{id_value}'"
        print(f"修改日志语句：{sql}")

        db_host = self.config["db_host"]
        db_port = self.config["db_port"]
        db_name = self.config["db_name"]
        db_user = self.config["db_user"]
        db_password = self.config["db_password"]
        db_helper = LuckDbMysqlHelperUtils(db_host, db_port, db_name, db_user, db_password)
        with db_helper as um:
            um.cursor.execute(sql)

        obj = self.read({
            "id": id_value
        })["data"][0]

        gitlab_file_service = LuckGitlabFileService(self.config)
        # 先删除，在添加
        read_files = gitlab_file_service.read({
            "project_id": parameters["project_id"],
            "branch_name": parameters["branch_name"],
            "commit_id": parameters["commit_id"]
        })["data"]
        for file in read_files:
            gitlab_file_service.delete({
                "id": file["id"]
            })
        for file in commit_new_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "new_file",
                "commit_file_diff": file["diff"]
            })
        for file in commit_renamed_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "renamed_file",
                "commit_file_diff": file["diff"]
            })
        for file in commit_deleted_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "deleted_file",
                "commit_file_diff": file["diff"]
            })
        for file in commit_updated_file_list:
            gitlab_file_service.add({
                "id": str(uuid.uuid4()),
                "project_id": parameters["project_id"],
                "branch_name": parameters["branch_name"],
                "commit_id": parameters["commit_id"],
                "commit_file_old_path": file["old_path"],
                "commit_file_new_path": file["new_path"],
                "commit_file_type": "updated_file",
                "commit_file_diff": file["diff"]
            })

        return {
            "code": LuckConstant.CODE_SUCCESS,
            "msg": "操作成功",
            "data": obj
        }

    # 查询日志
    def read(self, parameters):
        conditions = []
        for key, value in parameters.items():
            if value is not None:
                conditions.append(f"a.{key} = '{value}'")

        sql = f"select a.* from {self.TABLE_NAME} a where 1=1 "
        if conditions:
            sql += " AND " + " AND ".join(conditions)

        sql += " order by a.regt desc "
        db_host = self.config["db_host"]
        db_port = self.config["db_port"]
        db_name = self.config["db_name"]
        db_user = self.config["db_user"]
        db_password = self.config["db_password"]
        db_helper = LuckDbMysqlHelperUtils(db_host, db_port, db_name, db_user, db_password)
        with db_helper as um:
            um.cursor.execute(sql)

            # 初始化一个空列表来保存结果
            result_list = []

            # 遍历查询结果
            for row in um.cursor.fetchall():
                if row["regt"] is not None:
                    row["regt"] = datetime.strftime(row["regt"], "%Y-%m-%d %H:%M:%S")
                # 将字典添加到列表中
                result_list.append(row)

            print(f"查询日志条数：{len(result_list)}，数据：{result_list}")
            return {
                "code": LuckConstant.CODE_SUCCESS,
                "msg": "操作成功",
                "data": result_list
            }